package spring.aop.proxy;


import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import spring.aop.ProceedingJoinPoint;
import spring.aop.AopProcessor;

import java.lang.reflect.Method;

/**
 * @author cg
 * @date 2023/6/14 19:06
 */
public class CglibProxy implements MethodInterceptor {
    //被代理类
    private Object target;
    //由于cglib不能多重代理，所以将所有的代理功能放在一个责任链中执行
    private CglibChain cglibChain;

    public CglibProxy(Object target) {
        this.target = target;
        this.cglibChain = new CglibChain(target);
    }

    /**
     * 将aop方法转化为责任链并注册到责任链对象中
     * @param aopProcessor aop类
     */
    public void registCglibPoint(AopProcessor aopProcessor) {
        cglibChain.registCglibPoint(new CglibPoint() {
            @Override
            public Object proceed(CglibChain chain, Method method, Object[] args) {
                Object res = null;
                try {
                    Object newInstance = aopProcessor.getClazz().getConstructor().newInstance();
                    //将切面信息包装成ProceedingJoinPoint对象
                    ProceedingJoinPoint joinPoint = new ProceedingJoinPoint();
                    joinPoint.load(target,method,args);
                    //增强前方法
                    Method beforeMethod = aopProcessor.getBeforeMethod();
                    if (beforeMethod != null) beforeMethod.invoke(newInstance,joinPoint);
                    //执行本方法
                    res = chain.process(method, args);
                    //增强后方法
                    Method afterMethod = aopProcessor.getAfterMethod();
                    if (afterMethod != null) afterMethod.invoke(newInstance,joinPoint);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                return res;
            }
        });
    }

    /**
     * 获取代理对象
     * @return
     */
    public Object getProxyBean() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        Object o = enhancer.create();
        return o;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        cglibChain.resetIdx();
        return cglibChain.process(method, objects);
    }
}
